package game.games.rpg;

import game.gfx.ColoredChar;
import game.gfx.Colors;
import game.gfx.ConsoleColor;

import java.awt.Point;

public class Interface
{
    private int             width;
    private int             height;
    
    // this looks like a borderlayout
    // AAAAAA
    // BBCCDD
    // EEEEEE
    
    private int             topHeight;
    private ColoredChar[][] topBuffer;
    
    private int             bottomHeight;
    private ColoredChar[][] bottomBuffer;
    
    private int             leftWidth;
    private ColoredChar[][] leftBuffer;
    
    private int             rightWidth;
    private ColoredChar[][] rightBuffer;
    
    private int             roomWidth;
    private int             roomHeight;
    private Room            room;
    
    public Interface()
    {
        this.width = 0;
        this.height = 0;
        this.topHeight = 0;
        this.topBuffer = null;
        this.bottomHeight = 0;
        this.bottomBuffer = null;
        this.leftWidth = 0;
        this.leftBuffer = null;
        this.rightWidth = 0;
        this.rightBuffer = null;
        this.roomWidth = 0;
        this.roomHeight = 0;
        this.room = null;
    }
    
    public int getWidth()
    {
        return width;
    }
    
    public int getHeight()
    {
        return height;
    }
    
    public void setLeft(int width)
    {
        this.leftWidth  = width;
    }
    
    public void setRight(int width)
    {
        this.rightWidth  = width;
    }
    
    public void setTop(int height)
    {
        this.topHeight = height;
    }
    
    public void setBottom(int height)
    {
        this.bottomHeight = height;
    }
    
    public void setRoomSize(int width, int height)
    {
        this.roomWidth  = width;
        this.roomHeight = height;
        // calc size
        this.width  = leftWidth + roomWidth  + rightWidth;
        this.height = topHeight + roomHeight + bottomHeight;
        // build buffers
        this.topBuffer    = CharBufferUtil.generate2DCharBuffer(this.width,      this.topHeight,    ' ', ConsoleColor.DEFAULT);
        this.leftBuffer   = CharBufferUtil.generate2DCharBuffer(this.leftWidth,  this.roomHeight,   ' ', ConsoleColor.DEFAULT);
        this.rightBuffer  = CharBufferUtil.generate2DCharBuffer(this.rightWidth, this.roomHeight,   ' ', ConsoleColor.DEFAULT);
        this.bottomBuffer = CharBufferUtil.generate2DCharBuffer(this.width,      this.bottomHeight, ' ', ConsoleColor.DEFAULT);
    }
    
    public void setRoom(Room room)
    {
        this.room = room;
    }
    
    public int getRoomHeight()
    {
        return roomHeight;
    }

    public int getLeftWidth()
    {
        return leftWidth;
    }

    public int getRightWidth()
    {
        return rightWidth;
    }

    public int getRoomWidth()
    {
        return roomWidth;
    }

    public int getTopHeight()
    {
        return topHeight;
    }

    public int getBottomHeight()
    {
        return bottomHeight;
    }

    public ColoredChar[][] getLeftBuffer()
    {
        return leftBuffer;
    }

    public ColoredChar[][] getRightBuffer()
    {
        return rightBuffer;
    }

    public ColoredChar[][] getTopBuffer()
    {
        return topBuffer;
    }

    public ColoredChar[][] getBottomBuffer()
    {
        return bottomBuffer;
    }
    
    private boolean paintRoom(int x, int y)
    {
        return x >= leftWidth && x < width  - rightWidth &&
               y >= topHeight && y < height - bottomHeight;
    }
    
    private Point getRelativePoint(int x, int y)
    {
        // render level
        int startX = room.getPlayerPosition().x;
        int startY = room.getPlayerPosition().y;
        // do we need a relative x?
        int scrollingFactorX = roomWidth / 2;
        if (startX < scrollingFactorX)
        {
            startX = 0; 
        }
        else if (startX > (room.getWidth() - scrollingFactorX))
        {
            startX = (room.getWidth() - roomWidth);
        }
        else
        {
            startX = startX - scrollingFactorX;
        }
        if (startX < 0)
        {
            startX = 0;
        }
        // do we need a relative y?
        int scrollingFactorY = roomHeight / 2;
        if (startY < scrollingFactorY)
        {
            startY = 0; 
        }
        else if (startY > (room.getHeight() - scrollingFactorY))
        {
            startY = (room.getHeight() - roomHeight);
        }
        else
        {
            startY = startY - scrollingFactorY;
        }
        if (startY < 0)
        {
            startY = 0;
        }
        // relative xy in room coord
        x -= leftWidth;
        y -= topHeight;
        // add to relative start
        x += startX;
        y += startY;
        return new Point(x, y);
    }
    
    public ColoredChar get(int x, int y)
    {
        ColoredChar c = new ColoredChar('?', ConsoleColor.ERROR);
        // top?
        if (y < topHeight)
        {
            c = topBuffer[y][x];
        }
        // bottom?
        else if (y >= height - bottomHeight)
        {
            c = bottomBuffer[y - (topHeight + roomHeight)][x];
        }
        // center
        else
        {
            // left?
            if (x < leftWidth)
            {
                c = leftBuffer[y - topHeight][x];
            }
            // right
            else if (x >= width - rightWidth)
            {
                c = rightBuffer[y - topHeight][x - (leftWidth + roomWidth)];
            }
            // room
            else if (paintRoom(x, y))
            {
                try
                {
                    // relative xy in room coord
                    Point p = getRelativePoint(x, y);
                    c = room.getChar(p.x, p.y);
                }
                catch (IllegalArgumentException ex)
                {
                    // ignore
                }
            }
        }
        return c;
    }

    private void printTopBuffer()
    {
        if (getTopHeight() <= 0)
        {
            return;
        }
    }

    private void printLeftBuffer()
    {
        if (getLeftWidth() <= 0)
        {
            return;
        }
    }
    
    private void printRightBuffer()
    {
        if (getRightWidth() <= 0)
        {
            return;
        }
        ColoredChar[][] charBuffer = getRightBuffer();
        CharBufferUtil.fill(charBuffer, new Point(0,0), new Point(0, charBuffer.length - 1), '|', ConsoleColor.DEFAULT);
        int line = 0;
        // Player
        Player player = room.getPlayer();
        CharBufferUtil.fillString(charBuffer[line++], 1, player.getName() + " " + player.getLookingDirection().getChar(), new ConsoleColor(Colors.yellow, Colors.black));
        // Level
        CharBufferUtil.fillString(charBuffer[line++], 1, "Level " + player.getLevel(), new ConsoleColor(Colors.yellow, Colors.black));
        // Health / Attack
        CharBufferUtil.fillString(charBuffer[line++], 1, "Health: " + player.getHealth() + "/" + player.getMaxHealth(), new ConsoleColor(Colors.brown, Colors.black)); 
        CharBufferUtil.fillString(charBuffer[line++], 1, "Attack: " + player.getAttack(), new ConsoleColor(Colors.brown, Colors.black));
        // Space
        line++;
        line++;
        line++;
        // Monsters
        for (Point p : room.getMonsters().keySet())
        {
            if (room.isVisible(p))
            {
                Monster monster = room.getMonster(p.x, p.y);
                // Monster
                CharBufferUtil.fillString(charBuffer[line++], 1, "Monster " + monster.getName() + " " + monster.getLookingDirection().getChar(), ConsoleColor.DEFAULT);
                // Level
                CharBufferUtil.fillString(charBuffer[line++], 1, "Level " + monster.getLevel(), ConsoleColor.DEFAULT);
                // Health / Attack
                CharBufferUtil.fillString(charBuffer[line++], 1, "Health: " + monster.getHealth() + "/" + monster.getMaxHealth(), ConsoleColor.DEFAULT);
                CharBufferUtil.fillString(charBuffer[line++], 1, "Attack: " + monster.getAttack(), ConsoleColor.DEFAULT);
                line++;
            }
        }
        // clear rest
        for (;line < charBuffer.length;line++)
        {
            CharBufferUtil.fillString(charBuffer[line], 1, "", ConsoleColor.DEFAULT);
        }
    }

    private void printBottomBuffer()
    {
        if (getBottomHeight() <= 0)
        {
            return;
        }
        ColoredChar[][] charBuffer = getBottomBuffer();
        CharBufferUtil.createDoubleLinedBorder(charBuffer, new Point(0, 0), new Point(charBuffer[0].length - 1, charBuffer.length - 1), ConsoleColor.DEFAULT);
    }

    public void printBuffers()
    {
        printTopBuffer();
        printLeftBuffer();
        printRightBuffer();
        printBottomBuffer();
    }

}
